package covertjava.chat;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.*;
import java.net.InetAddress;

/**
 * <p>Encapsulates all logic that is needed to send and received messages via TCP/IP
 * Uses RMI as a communication protocol. ChatServer acts both as an RMI server to
 * receive incoming messages, and RMI client to send outgoing messages.</p>
 * <p>Copyright: Copyright (c) 2004 Sams Publishing</p>
 * @author Alex Kalinovsky
 * @version 1.0
 */
public class ChatServer extends UnicastRemoteObject implements ChatServerRemote {

    protected static ChatServer instance;
    // Default chat port is different from RMI port to avoid conflicts with other
    // Java apps that might be running on local host
    protected int registryPort = Registry.REGISTRY_PORT + 50;
    protected Registry registry;
    MessageListener messageListener;
    String hostName;
    String userName;


    protected ChatServer() throws Exception {
    }


    public static ChatServer getInstance() throws Exception {
        if (instance == null)
            instance = new ChatServer();
        return instance;
    }


    public void init() throws Exception {
        System.out.println("Initializing the chat server...");
        String portString = System.getProperty("chat.serverPort");
        if (portString != null)
            this.registryPort = Integer.parseInt(portString);

        this.registry = getRegistry(this.registryPort);

        Object anotherInstance = null;
        String url = "//127.0.0.1:" + this.registryPort + "/chatserver";
        try {
            anotherInstance = Naming.lookup(url);
        }
        catch (Exception x) {
            // The other instance is not running
        }
        if (anotherInstance != null)
            throw new Exception("Another instance of ChatApplication is already running on this machine");

        Naming.rebind(url, this);

        this.hostName = InetAddress.getLocalHost().getHostName();
        this.userName = System.getProperty("user.name");

        System.out.println("ChatApplication server initialized");
    }


    public void sendMessage(String host, String message) throws Exception {
        if (host == null || host.trim().length() == 0)
            throw new Exception ("Please specify host name");

        System.out.println("Sending message to host " + host + ": " + message);
        String url = "//" + host + ":" + this.registryPort + "/chatserver";
        ChatServerRemote remoteServer = (ChatServerRemote)Naming.lookup(url);

        MessageInfo messageInfo = new MessageInfo(this.hostName, this.userName);
        remoteServer.receiveMessage(message, messageInfo);
        System.out.println("Message sent to host " + host);
    }


    public void setMessageListener(MessageListener listener) {
        this.messageListener = listener;
    }


    public MessageListener getMessageListener() {
        return this.messageListener;
    }


    public Registry getRegistry(int port) throws Exception {
        System.out.println("Trying to get the registry on port " + port);
        Registry registry = null;
        try {
            // First try to get the registry on default port. We can't export our own registry on a different port if there is one registry already running
            registry = LocateRegistry.getRegistry(port);
            registry.list();    // Call list to make sure the registry is actually usable
        } catch (Exception x) {
            System.out.println("Registry was not running, trying to create one...");
            registry = LocateRegistry.createRegistry(port);
            registry.list();    // Call list to make sure the registry is actually usable
        }

        return registry;
    }


    public void receiveMessage(String message, MessageInfo messageInfo) throws RemoteException {
        System.out.println("Received message from host " + messageInfo.getHostName());
        if (this.messageListener != null)
            this.messageListener.messageReceived(message, messageInfo);
    }

}
